/// @Classname : HcBaseButton
/// @Author :
/// @Time : 2023-10-11 9:32
/// @Description : 基础的按钮封装

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

import 'package:hc_ui/config/hc_customer_config.dart';

import 'package:hc_ui/theme/hc_button_theme.dart';
import 'package:hc_ui/utils/hc_click_util.dart';
import 'package:hc_ui/widget/icon_text/hc_icon_text.dart';

class HcBaseButton extends StatefulWidget {
  //是否禁用
  final bool disabled;

  //抬升高度
  final double elevation;

  //文字内容
  final String? text;

  //是否展示loading状态
  final bool loading;

  final bool stateIconReverse;
  final MainAxisAlignment stateIconAlignment;
  final Gradient? gradient;

  //状态Icon
  final Widget? stateIcon;

  //点击的状态
  final VoidCallback? onPressed;

  //长按的状态
  final VoidCallback? longPress;

  //子组件 优先级大于文字
  final Widget? child;

  //主题样式
  final HcButtonTheme? themeData;

  const HcBaseButton(
      {Key? key,
      this.disabled = false,
      this.text,
      this.loading = false,
      this.onPressed,
      this.longPress,
      required this.elevation,
      this.child,
      this.themeData,
      this.stateIcon,
      this.stateIconReverse = false,
      this.stateIconAlignment = MainAxisAlignment.start,
      this.gradient})
      : super(key: key);

  HcBaseButton.text(
      {Key? key,
      Color? textColor,
      Color? disabledTextColor,
      Color? splashColor,
      Color? highlightColor,
      Size? minSize,
      Size? maxSize,
      int? maxLines,
      double? fontSize,
      FontWeight? fontWeight,
      TextStyle? textStyle,
      EdgeInsets? padding,
      this.disabled = false,
      required this.text,
      this.loading = false,
      required this.onPressed,
      this.longPress,
      this.stateIcon,
      this.child,
      this.stateIconReverse = false,
      this.stateIconAlignment = MainAxisAlignment.start,
      this.gradient})
      : elevation = 0,
        themeData = HcButtonTheme(
            miniSize: minSize,
            maxSize: maxSize,
            maxLines: maxLines,
            textColor: textColor,
            splashColor: splashColor,
            highlightColor: highlightColor,
            disabledTextColor: disabledTextColor,
            backgroundColor: Colors.transparent,
            borderRadius: BorderRadius.circular(4),
            padding: padding,
            textStyle: TextStyle(fontSize: fontSize, fontWeight: fontWeight)
                .merge(textStyle),
            disabledBackgroundColor: Colors.transparent),
        super(key: key);

  HcBaseButton.outline(
      {required this.disabled,
      this.text,
      required this.loading,
      this.onPressed,
      this.longPress,
      this.child,
      required Color borderColor,
      required double borderWidth,
      BorderRadius? borderRadius,
      Color? textColor,
      Color? disabledTextColor,
      Color? splashColor,
      Color? highlightColor,
      Size? minSize,
      Size? maxSize,
      int? maxLines,
      double? fontSize,
      FontWeight? fontWeight,
      TextStyle? textStyle,
      EdgeInsets? padding,
      super.key,
      this.stateIcon,
      this.stateIconReverse = false,
      this.stateIconAlignment = MainAxisAlignment.start,
      this.gradient})
      : elevation = 0,
        themeData = HcButtonTheme(
            miniSize: minSize,
            maxSize: maxSize,
            maxLines: maxLines,
            textColor: textColor,
            splashColor: splashColor,
            highlightColor: highlightColor,
            disabledTextColor: disabledTextColor,
            borderRadius: borderRadius,
            side: BorderSide(color: borderColor, width: borderWidth),
            backgroundColor: Colors.transparent,
            padding: padding,
            textStyle: TextStyle(fontSize: fontSize, fontWeight: fontWeight)
                .merge(textStyle),
            disabledBackgroundColor: Colors.transparent);

  @override
  State<HcBaseButton> createState() => _HcBaseButtonState();
}

class _HcBaseButtonState extends State<HcBaseButton> {
  double elevation = 2;

  @override
  void initState() {
    super.initState();
    elevation = (widget.disabled || widget.loading) ? 0 : widget.elevation;
  }

  @override
  void didUpdateWidget(covariant HcBaseButton oldWidget) {
    super.didUpdateWidget(oldWidget);
    elevation = (widget.disabled || widget.loading) ? 0 : widget.elevation;
  }

  @override
  Widget build(BuildContext context) {
    bool disabled = widget.disabled || widget.loading;
    HcButtonTheme buttonTheme = widget.themeData ?? HcButtonTheme();
    buttonTheme = HcCustomerConfig().allTheme.buttonTheme.merge(buttonTheme);
    return Semantics(
      container: true,
      enabled: !disabled,
      button: true,
      child: _InputPadding(
          miniSize: buttonTheme.miniSize,
          child: Container(
            decoration: BoxDecoration(
                gradient: widget.gradient,
                borderRadius: buttonTheme.borderRadius),
            constraints: BoxConstraints(
              minWidth: buttonTheme.miniSize.width,
              minHeight: buttonTheme.miniSize.height,
              maxWidth: buttonTheme.maxSize.width,
              maxHeight: buttonTheme.maxSize.height,
            ),
            child: Material(
              type: MaterialType.button,
              color: disabled
                  ? buttonTheme.disabledBackgroundColor
                  : buttonTheme.backgroundColor,
              elevation: elevation,
              shape: buttonTheme.shape,
              child: InkWell(
                splashColor: buttonTheme.splashColor,
                highlightColor: buttonTheme.highlightColor,
                customBorder: buttonTheme.shape,
                onTapDown: disabled ? null : (details) => changeElevation(6),
                onTapUp: disabled
                    ? null
                    : (details) => changeElevation(widget.elevation),
                onTap: disabled
                    ? null
                    : () => {
                          if (HcClickUtil.enableResponses())
                            {
                              if (widget.onPressed != null)
                                {widget.onPressed!()}
                            }
                        },
                child: Container(
                  padding: buttonTheme.padding,
                  child: Align(
                    widthFactor: 1,
                    heightFactor: 1,
                    child: widget.child ??
                        HcIconText(
                          spacing: buttonTheme.stateIconSpacing,
                          direction: Axis.horizontal,
                          reverse: widget.stateIconReverse,
                          icon: widget.loading
                              ? SizedBox(
                                  width: buttonTheme.textStyle.fontSize,
                                  height: buttonTheme.textStyle.fontSize,
                                  child: CircularProgressIndicator(
                                      strokeWidth:
                                          buttonTheme.commonTheme.lineBase),
                                )
                              : widget.stateIcon != null
                                  ? IconTheme(
                                      data: IconThemeData(
                                          color: buttonTheme.stateIconColor,
                                          size: buttonTheme.stateIconSize),
                                      child: widget.stateIcon!)
                                  : null,
                          label: Text(
                            widget.text ?? '',
                            maxLines: buttonTheme.maxLines,
                            overflow: TextOverflow.ellipsis,
                            style: buttonTheme.textStyle.merge(TextStyle(
                                color: disabled
                                    ? buttonTheme.disabledTextColor
                                    : buttonTheme.textColor)),
                          ),
                          mainAxisSize: MainAxisSize.min,
                        ),
                  ),
                ),
              ),
            ),
          )),
    );
  }

  void changeElevation(double value) {
    setState(() {
      elevation = widget.elevation > 0 ? (widget.elevation + value) : 0;
    });
  }
}

class _InputPadding extends SingleChildRenderObjectWidget {
  final Size miniSize;

  const _InputPadding({required this.miniSize, required super.child});

  @override
  RenderObject createRenderObject(BuildContext context) {
    return _RenderInputPadding(miniSize);
  }
}

class _RenderInputPadding extends RenderShiftedBox {
  Size _minSize;

  Size get minSize => _minSize;

  set minSize(Size value) {
    if (_minSize == value) {
      return;
    }
    _minSize = value;
    markNeedsLayout();
  }

  _RenderInputPadding(this._minSize, [RenderBox? child]) : super(child);

  @override
  double computeMinIntrinsicWidth(double height) {
    if (child != null) {
      return max(child!.getMinIntrinsicWidth(height), minSize.width);
    }
    return 0.0;
  }

  @override
  double computeMinIntrinsicHeight(double width) {
    if (child != null) {
      return max(child!.getMinIntrinsicHeight(width), minSize.height);
    }
    return 0.0;
  }

  @override
  double computeMaxIntrinsicWidth(double height) {
    if (child != null) {
      return max(child!.getMaxIntrinsicWidth(height), minSize.width);
    }
    return 0.0;
  }

  @override
  double computeMaxIntrinsicHeight(double width) {
    if (child != null) {
      return max(child!.getMaxIntrinsicHeight(width), minSize.height);
    }
    return 0.0;
  }

  Size _computeSize(
      {required BoxConstraints constraints,
      required ChildLayouter layoutChild}) {
    if (child != null) {
      final Size childSize = layoutChild(child!, constraints);
      final double height = max(childSize.width, minSize.width);
      final double width = max(childSize.height, minSize.height);
      return constraints.constrain(Size(height, width));
    }
    return Size.zero;
  }

  @override
  Size computeDryLayout(BoxConstraints constraints) {
    return _computeSize(
      constraints: constraints,
      layoutChild: ChildLayoutHelper.dryLayoutChild,
    );
  }

  @override
  void performLayout() {
    size = _computeSize(
      constraints: constraints,
      layoutChild: ChildLayoutHelper.layoutChild,
    );
    if (child != null) {
      final BoxParentData childParentData = child!.parentData! as BoxParentData;
      childParentData.offset =
          Alignment.center.alongOffset(size - child!.size as Offset);
    }
  }

  @override
  bool hitTest(BoxHitTestResult result, {required Offset position}) {
    if (super.hitTest(result, position: position)) {
      return true;
    }
    final Offset center = child!.size.center(Offset.zero);
    return result.addWithRawTransform(
      transform: MatrixUtils.forceToPoint(center),
      position: center,
      hitTest: (BoxHitTestResult result, Offset position) {
        assert(position == center);
        return child!.hitTest(result, position: center);
      },
    );
  }
}
